package com.atguigu.gmall.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.exception.OrderException;
import com.atguigu.gmall.wms.vo.SkuLockVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.wms.mapper.WareSkuMapper;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private WareSkuMapper wareSkuMapper;

    private static final String LOCK_PREFIX = "stock:lock:";
    private static final String KEY_PREFIX = "stock:info:";

    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<WareSkuEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageResultVo(page);
    }

    @Transactional
    @Override
    public List<SkuLockVo> checkAndLock(List<SkuLockVo> lockVos, String orderToken) {
        if (CollectionUtils.isEmpty(lockVos)){
            throw new OrderException("您没有要购买的商品");
        }

        //遍历 验库存并锁库存
        lockVos.forEach(skuLockVo -> {
            this.checkLock(skuLockVo);
        });

        //判断是否存在锁定失败的商品，如果存在，则把所有锁定成功的商品库存解锁
        if (lockVos.stream().anyMatch(skuLockVo -> !skuLockVo.getLock())){
            //遍历所有锁定成功的商品，解锁库存
            lockVos.stream().filter(SkuLockVo::getLock).forEach(skuLockVo -> {
                this.wareSkuMapper.unlock(skuLockVo.getWareSkuId(), skuLockVo.getCount());
            });

            //锁定失败情况下，返回所有商品的锁定情况
            return lockVos;
        }

        //为了方便将来解锁库存或者减库存，需要把库存锁定信息，以orderToken作为key 缓存到redis中
        this.redisTemplate.opsForValue().set(KEY_PREFIX + orderToken, JSON.toJSONString(lockVos), 30, TimeUnit.HOURS);

        //如果都锁定成功，返回null
        return null;
    }

    private void checkLock(SkuLockVo lockVo) {
        RLock lock = this.redissonClient.getLock(LOCK_PREFIX + lockVo.getSkuId());
        lock.lock();

        //验库存
        List<WareSkuEntity> wareSkuEntities = this.wareSkuMapper.check(lockVo.getSkuId(), lockVo.getCount());
        //如果没有一个仓库满足购买要求，则验库存锁库存失败
        if (CollectionUtils.isEmpty(wareSkuEntities)){
            lockVo.setLock(false);
            return;
        }

        try {
            //锁库存：这里去第一个仓库
            WareSkuEntity wareSkuEntity = wareSkuEntities.get(0);
            wareSkuEntity.setStockLocked(wareSkuEntity.getStockLocked() + lockVo.getCount());
            if (this.updateById(wareSkuEntity)){
                lockVo.setLock(true);
                //锁库存成功的情况下，记录锁定成功的仓库id
                lockVo.setWareSkuId(wareSkuEntity.getId());
            }else{
                lockVo.setLock(false);
            }
        } finally {
            lock.unlock();
        }
    }

}
